﻿using QQZiFramework;
using System;
using System.Collections.Generic;
using System.Data;
using Microsoft.Extensions.Caching.Memory;
using System.Text;
using System.Text.RegularExpressions;
using System.Collections;
using System.Reflection;

namespace QQZiFramework.Membership
{
    public class MembershipBLL : QQZiFramework.QQZIBaseBusiness
    {
        /// <summary>
        /// 通过微信openid获取用户
        /// </summary>
        /// <param name="openId"></param>
        /// <returns></returns>
        public BaseUser GetUserIdByWeixin(string openId)
        {
            if (openId == null) { return null; }
            else
            {
                QueryParam qp = new QueryParam() { entityType = Context.Membership.UserType, queryField = "*" };
                qp.AddWhere("WeiXin", openId);
                qp.AddWhere("Status", "> -1");
                return (BaseUser) Context.DoGetOne(qp,null); 
            }
        }
        /// <summary>
        /// 通过微信unionId获取用户
        /// </summary>
        /// <param name="openId"></param>
        /// <returns></returns>
        public BaseUser GetUserIdByWeixinUnionId(string unionId)
        {
            if (unionId == null) { return null; }
            else
            {
                QueryParam qp = new QueryParam() { entityType = Context.Membership.UserType, queryField = "*" };
                qp.AddWhere("Unionid", unionId);
                qp.AddWhere("Status", "> -1");
                return (BaseUser)Context.DoGetOne(qp, null);
            }
        }


        private DataTable GetAllRoleUserTable()
        {
            string cacheKey = "permissions-role-allRoles-table";
            return Context.GetRedisDatabase().GetOrCreate(cacheKey, X =>
            {
                X.ExpiresAt = DateTime.Now.AddMinutes(10);
                return Context.QueryTable("select A0_RoleUsers.* ,A0_Roles.Name  from A0_RoleUsers join A0_Roles on A0_Roles.Id = A0_RoleUsers.RoleId ");
            });
        }



        /// <summary>
        /// 获取用记角色ID，以逗号隔开
        /// </summary>
        /// <returns></returns>
        public string GetUserRoles(int userid)
        {
            string roleStr = "";
            DataTable roleTable = GetAllRoleUserTable();
            DataRow[] rows = roleTable.Select("UserId = " + userid);
            //DataTable dt = context.QueryTable("select ru.RoleID from A0_RoleUsers ru where ru.UserId = " + userid);
            foreach (DataRow dr in rows)
            {
                roleStr += "," + dr["RoleId"].ToString();
            }
            if (roleStr.Length > 0) roleStr = roleStr.Substring(1);
            else
            {
                //如果没有角色信息，则默认为网站用户
                object scalar = Context.ExecScalar("select ID from A0_Roles  where Name = 'webusers'");
                //if (scalar == null || scalar == DBNull.Value) throw new ClientException("没有配置用户角色，也没有网站用户webusers的角色信息");
                if (scalar == null || scalar == DBNull.Value) roleStr = null;
                else roleStr = scalar.ToString();
            }
            return roleStr;
        }

        /// <summary>
        /// 是否是管理员
        /// </summary>
        public bool IsAdministrator(int userId)
        {
            object obj = Context.GetArgument("IsAdministrator");
            if (obj != null)
            {
                return (bool)obj;
            }
            //获取用户角色
            DataTable roleTable = GetAllRoleUserTable();
            DataRow[] rows = roleTable.Select("UserId = " + userId + " and Name='administrators'");
            bool isAdmin = rows.Length > 0;
            Context.SetArgument("IsAdministrator", isAdmin);
            return isAdmin;
        }

        /// <summary>
        /// 是否是管理员
        /// </summary>
        public bool HasAdministratorRole(string roles)
        {
            object scalar = Context.ExecScalar("select ID from A0_Roles  where Name = 'administrators'");
            string roleId = scalar.ToString();
            if (roles != null)
            {
                foreach (string str in roles.Split(','))
                {
                    if (str.Equals(roleId)) return true;
                }
            }
            return false;
        }

        /// <summary>
        /// 获取角色Id
        /// </summary>
        public int GetRoleId(string roleName)
        {
            object scalar = Context.ExecScalar("select ID from A0_Roles  where Name = '" + roleName + "'");
            if (scalar != null && scalar != DBNull.Value) return Convert.ToInt32(scalar);
            else return 0;
        }

        public void ClearPermissionCache()
        {
            Context.GetRedisDatabase().DeleteRedisItems("permissions-role*");
            Context.ChearCacheLike("permissions-role");
        }


        /// <summary>
        /// 获取用户权限树型列表
        /// </summary>
        /// <returns></returns>
        public List<Permission> GetUserPermissions(int userid, LoginPlatfromId platform = LoginPlatfromId.Admin)
        {

            //获取用户角色
            string roleStr = GetUserRoles(userid);
            return GetRolesPermissions(userid, roleStr, platform);

        }

        /// <summary>
        /// 获取用户权限树型列表
        /// </summary>
        /// <returns></returns>
        public List<Permission> GetRolesPermissions(int userid, string roleStr, LoginPlatfromId platform = LoginPlatfromId.Admin)
        {


            //if (string.IsNullOrEmpty(roleStr)) throw new ClientException("没有配置角色!");
            string cacheKey = null;
            ChildAccount childAccount = null;
            if (string.IsNullOrEmpty(roleStr) && userid > 0)
            {
                childAccount = Context.QuerySingle<ChildAccount>(new { UserId = userid });
                if (childAccount == null) throw new ClientException("没有配置角色!");
                if (childAccount.Status == -1) throw new ClientException("该账号已被禁用!");
                cacheKey = Context.Membership.OnCacheKey("permissions-role-child" + childAccount.Id);
            }
            else
            {
                cacheKey = Context.Membership.OnCacheKey("permissions-role" + roleStr);
            }
            cacheKey += "-" + platform;
            //if (string.IsNullOrEmpty(roleStr)) throw new ClientException("没有配置角色!");
            List<Permission> lst = Context.GetOrCreateCache(cacheKey, x =>
            {
                string platformName = Enum.GetName(typeof(LoginPlatfromId), platform);
                string parentVal = Context.GetSettingValue<string>("Basic:Platform_Permission_Root:" + platformName);
                //查询权限树
                string permissionFilter = "";
                bool isAdministrator = HasAdministratorRole(roleStr);
                if (isAdministrator)
                {
                    //是管理员，不用过滤权限点
                    permissionFilter = "is not null";
                }
                else
                {
                    DataTable dt = null;
                    //获取配置的权限点
                    if (cacheKey.IndexOf("child") == -1)
                    {
                        //角色权限
                        dt = Context.QueryTable("select rp.PermissionCode from A0_RolePermissions rp where rp.RoleId in (" + roleStr + ") ");
                    }
                    else
                    {
                        //子帐号权限
                        dt = Context.QueryTable("select acp.PermissionCode from A0_ChildAccountPermissions acp where acp.ChildAccountId=" + childAccount.Id);
                    }
                    if (dt.Rows.Count == 0) { throw new ClientException("没有任何权限!"); }
                    foreach (DataRow dr in dt.Rows) permissionFilter += ",'" + dr[0].ToString() + "'";
                    if (permissionFilter.Length > 0) permissionFilter = "in (" + permissionFilter.Substring(1) + ")";
                }
                x.SetAbsoluteExpiration(TimeSpan.FromMinutes(15));
                return Context.QueryTree<Permission>(null, new { Code__Custom =WhereItem_Custom.Create(permissionFilter,null) }, "OrderIndex", parentVal: parentVal, strictModel: false);

            });


            return lst;

        }

        public void SaveChildUserPemissions(int childId, string permissions)
        {
            Context.ExecuteCommand("delete A0_ChildAccountPermissions where ChildAccountId =" + childId);
            if (permissions != null && permissions.Length > 0)
            {
                foreach (string permissionId in permissions.Split(','))
                {
                    ChildAccountPermission cap = new ChildAccountPermission() { ChildAccountId = childId, PermissionCode = permissionId };
                    Context.DoSave(cap);
                }
            }
            //sql = sql + "  insert A0_RolePermissions values" + rolePermission;

        }

        /// <summary>
        /// 判断用户是否具有该权限
        /// </summary>
        /// <param name="userid"></param>
        /// <param name="permission"></param>
        /// <returns></returns>
        public bool HasPermisson(int userid, string permission, LoginPlatfromId platform)
        {
            if (IsAdministrator(userid)) return true;
            List<Permission> lst = GetUserPermissions(userid, platform);
            Permission p = FindPermission(lst, permission.ToLower());
            return p != null;
        }

        public Permission FindPermisson(int userid, string permission, LoginPlatfromId platform)
        {
            List<Permission> lst = GetUserPermissions(userid, platform);
            Permission p = FindPermission(lst, permission.ToLower());
            return p;
        }

        /// <summary>
        /// 通过菜单获取权限名称
        /// </summary>
        public Permission GetPermissionByMenu(int userId, string menu, LoginPlatfromId platform)
        {
            List<Permission> lst = GetUserPermissions(userId, platform);
            return FindPermissionByMenu(lst, menu.ToLower(), platform);
        }

        private Permission FindPermissionByMenu(List<Permission> lst, string menu, LoginPlatfromId platform)
        {
            foreach (Permission p in lst)
            {
                if (p.MenuUrl != null && p.MenuUrl.ToLower() == menu) return p;
                else
                {
                    if (p.Children.Count > 0)
                    {
                        Permission pFind = FindPermissionByMenu(p.Children.ToList(), menu);
                        if (pFind != null) return pFind;
                    }
                }
            }
            return null;
        }
        private Permission FindPermissionByMenu(List<ITreeDBEntity> lst, string menu)
        {
            foreach (Permission p in lst)
            {
                if (p.MenuUrl != null && p.MenuUrl.ToLower() == menu) return p;
                else
                {
                    if (p.Children.Count > 0)
                    {
                        Permission pFind = FindPermissionByMenu(p.Children.ToList(), menu);
                        if (pFind != null) return pFind;
                    }
                }
            }
            return null;
        }

        /// <summary>
        /// 用户是否具有指定的角色
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="roleName"></param>
        /// <returns></returns>
        public bool HasRole(int userId, string roleName)
        {
            string sql = "select count(0) FROM A0_RoleUsers ru join A0_Roles  r on ru.RoleID = r.ID where r.Name='" + roleName + "' and UserId =" + userId;
            object scalar = Context.ExecScalar(sql);
            if (scalar == null || scalar == DBNull.Value || scalar.Equals(0)) return false;
            else return true;
        }
        private Permission FindPermission(List<ITreeDBEntity> lst, string permission)
        {
            foreach (Permission p in lst)
            {
                if (p.Name.ToLower() == permission) return p;
                else
                {
                    if (p.Children.Count > 0)
                    {
                        Permission pFind = FindPermission(p.Children.ToList(), permission);
                        if (pFind != null) return pFind;
                    }
                }
            }
            return null;
        }
        private Permission FindPermission(List<Permission> lst, string permission)
        {
            foreach (Permission p in lst)
            {
                if (p.Name.ToLower() == permission) return p;
                else
                {
                    if (p.Children.Count > 0)
                    {
                        Permission pFind = FindPermission(p.Children.ToList(), permission);
                        if (pFind != null) return pFind;
                    }
                }
            }
            return null;
        }


        /// <summary>
        /// 获取具有某个权限的角色ID集合
        /// </summary>
        /// <param name="excludeAdministrator">排除管理员（如果没有其它角色，则不排除）</param>
        /// <returns></returns>
        public string GetPermissionRoles(string permission, bool excludeAdministrator = false)
        {
            string sql = "select RoleId from A0_RolePermissions a join A0_Permissions b on a.PermissionCode = b.Code and b.Name = '" + permission + "'";
            if (excludeAdministrator)
            {
                sql += " and roleId <> (select id from A0_Roles where Name='administrators')";
            }
            DataTable dt = Context.QueryTable(sql);
            string str = "";
            foreach (DataRow dr in dt.Rows) { str += "," + dr["RoleId"]; }
            if (str.Length > 0) str = str.Substring(1);
            else if (excludeAdministrator)
            {
                str = GetAdministrator().Id.ToString();
            }
            return str;
        }

        /// <summary>
        /// 获取角色用户
        /// </summary>
        /// <param name="roles">角色编号集合，以逗号隔开</param>
        /// <param name="filterColumn">user列过滤，以逗号隔开</param>
        /// <returns></returns>
        public List<BaseUser> GetRoleUsers(string roles, string filterColumn)
        {
            if (roles.IndexOf(',') == -1) roles = "'" + roles + "'";
            return Context.QueryMany<BaseUser>(new { UserId = "in (select userid from A0_RoleUsers where RoleId in (" + roles + ") )" },null, filterColumn);

        }
        /// <summary>
        /// 获取角色的权限列表
        /// </summary>
        /// <param name="roleId"></param>
        /// <returns></returns>
        public DataTable GetRolePermissions(int roleId)
        {
            string sql = string.Format(@"select code as id,ParentCode as pId, Title as name,(case when b.PermissionCode is not null then 'true' else 'false' end )as checked, 'true' as [open] 
from A0_Permissions as a 
left join A0_RolePermissions as b on a.code=b.Permissioncode and b.RoleId={0}", roleId);

            return Context.QueryTable(sql);
        }

        public DataTable GetAdminUserRole(int UserId)
        {
            string sql = string.Format("select a.id,0 as pid, Title as name,(case when b.RoleID  is not null then 'true' else 'false' end )as checked, 'true' as [open] from A0_Roles as a left join A0_RoleUsers as b on a.Id=b.RoleID and b.UserId ={0}", UserId);

            return Context.QueryTable(sql);
        }
        public void SaveRolePemissions(int roleId, string permissions)
        {
            Context.ExecuteCommand("delete A0_RolePermissions where RoleId =" + roleId);
            if (permissions != null && permissions.Length > 0)
            {
                foreach (string permissionId in permissions.Split(','))
                {
                    RolePermission rp = new RolePermission() { RoleId = roleId, PermissionCode = permissionId };
                    Context.DoSave(rp);
                }
            }
            //sql = sql + "  insert A0_RolePermissions values" + rolePermission;

        }

        public void SaveAdminRole(int UserId, string roles, string AdminStatus)
        {
            string sql = "delete A0_RoleUsers where UserId =" + UserId;
            sql = sql + " update A1_AdminUsers set adminStatus=" + AdminStatus + " where UserId=" + UserId;

            Context.ExecuteCommand(sql);
            if (roles != null && roles.Length > 0)
            {
                foreach (string roleId in roles.Split(','))
                {
                    RoleUser ru = new RoleUser() { RoleId = Convert.ToInt32(roleId), UserID = UserId };
                    Context.DoSave(ru);
                }
            }
            ClearPermissionCache();
        }

        //public void SaveAdminRole(string UserId, string AdminUserRole, string AdminStatus, string AdminStoreID)
        //{
        //    string sql = "delete A0_RoleUsers where UserId =" + UserId;
        //    sql = sql + "insert A0_RoleUsers values" + AdminUserRole;
        //    sql = sql + "update A1_AdminUsers set adminStatus=" + AdminStatus + " where UserId=" + UserId;
        //    sql = sql + "update A0_Users set StoreID=" + AdminStoreID + "  where UserId=" + UserId;
        //    using (DBContext context = new DBContext())
        //    {
        //        context.ExecuteCommand(sql);
        //    }

        //}



        //public void addAdminUser(string userId)
        //{
        //    string sql = string.Format("if not exists(select * from A1_AdminUsers where UserId= {0}) insert into A1_AdminUsers(UserId,OperatorId) values({0},{1})", userId,Context.LoginUser.UserId);
        //    Context.ExecuteCommand(sql);
        //}



        /// <summary>
        /// 获取角色用户
        /// </summary>
        /// <param name="roles">角色编号集合，以逗号隔开</param>
        /// <param name="filterColumn">user列过滤，以逗号隔开</param>
        /// <returns></returns>
        public List<BaseUser> GetUsersByRoleName(string roleName, string filterColumn)
        {
            return Context.QueryMany<BaseUser>(new { UserId = "in (select userid from A0_RoleUsers where RoleId = (select id from A0_Roles where Name = '" + roleName + "') )" },null, filterColumn);
        }

        /// <summary>
        /// 更新最后登陆时间  user
        /// </summary>
        /// <param name="UserId"></param>
        //public void UpdateLastLoginTime(int UserId)
        //{
        //    using (DBContext context = new DBContext())
        //    {

        //        context.ExecuteCommand("update A0_Users set LastLoginTime = '" + DateTime.Now + "' where UserId=" + UserId);
        //    }
        //}
        /// <summary>
        /// 更新最后登陆时间  A1_AdminUsers
        /// </summary>
        /// <param name="UserId"></param>
        //public void UpdateAdminLastLoginTime(int UserId)
        //{
        //    using (DBContext context = new DBContext())
        //    {
        //        context.ExecuteCommand("update A1_AdminUsers set LastLoginTime='" + Convert.ToString(DateTime.Now) + "' where UserId=" + UserId);
        //    }
        //}
        /// <summary>
        /// 保存 用户登录注销记录
        /// <param name="ActionType">0:登录，1：注销</param>
        /// </summary>
        public void SaveUserRecord(int UserId, string cityId, string location, int Device, int ActionType, int isAdmin, string Terminal, string client, string ip, string PushId = null, string Coordinates = null)
        {

            LoginRecords lg = new LoginRecords();
            lg.UserId = UserId;
            lg.CreateTime = DateTime.Now;
            lg.Device = Device;
            lg.ActionType = ActionType;
            lg.isAdmin = isAdmin;
            lg.Terminal = Terminal;
            lg.CityId = cityId;
            lg.Location = location;
            lg.Client = client;
            lg.Coordinates = Coordinates;
            lg.Ip = ip;
            Context.DoSave(lg);
            string nowStr = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
            //string sql = "insert into A0_LoginRecords(UserId,CreateTime,Device,ActionType,isAdmin,Terminal,Client,Ip) values(" + UserId + ",'" + DateTime.Now + "'," + Device + "," + ActionType + "," + isAdmin + ",'" + Terminal + "','" + client + "','" + ip + "')";
            //Context.ExecuteCommand(sql);
            //更新最后登录时间
            if (isAdmin == 0)//这个是用户登录
            {
                if (!string.IsNullOrEmpty(Terminal))
                {
                    //APP,更新User的AppTermId
                    if (ActionType == 0)
                    {
                        //如果终端之前有登录过其它的账号，将期AppTermId清除

                        DataTable dt = Context.QueryTable("select UserId from A0_Users where AppTermId='" + Terminal + "' and  UserId <> " + UserId);
                        foreach (DataRow dr in dt.Rows)
                        {
                            int otherUserId = (int)dr["UserId"];
                            Context.ExecuteCommand("update A0_Users set AppTermId=null,PushId=null where UserId = " + otherUserId);
                            DeleteItemInCache(Context.Membership.UserType, otherUserId);
                        }
                        //int cc = Context.ExecuteCommand("update A0_Users set AppTermId=null where AppTermId='" + Terminal + "' and  UserId <> " + UserId);
                        //if (cc > 0)
                        //{
                        //    //把登录记录表里该终端号其它的登录记录标记为已注销
                        //    List<BaseUser> otherUser = Context.QueryManySql<BaseUser>("select UserId,Device,1,isAdmin,Terminal from A0_LoginRecords where Terminal='" + Terminal + "' and ActionType = 0 and UserId <> " + UserId);
                        //    foreach(BaseUser logOffu in otherUser){
                        //        LoginRecords record =new LoginRecords(){ UserId = logOffu.UserId,CreateTime = DateTime.Now, ActionType =1,isAdmin = isAdmin, Terminal =Terminal, Device =Device};
                        //        Context.DoSave(record);
                        //        //清除该用户的redis
                        //        DeleteItemInCache(Context.Membership.UserType, logOffu.UserId);

                        //    }                          

                        //}
                        //关联当前用户和终端
                        Context.ExecuteCommand("update A0_Users set AppTermId='" + Terminal + "', LastLoginTime = '" + nowStr + "',PushId = '" + PushId + "' where UserId=" + UserId);
                    }
                    else
                    {
                        //注销：清除该用户的终端关联
                        Context.ExecuteCommand("update A0_Users set AppTermId=null, LastLoginTime = '" + nowStr + "',PushId =null where UserId=" + UserId + " and AppTermId='" + Terminal + "'");

                    }
                }
                else
                {
                    Context.ExecuteCommand("update A0_Users set LastLoginTime = '" + nowStr + "' where UserId=" + UserId);
                }
            }
            else //就是isadmin 为1 是运营平台登录
            {
                Context.ExecuteCommand("update A1_AdminUsers set LastLoginTime='" + nowStr + "' where UserId=" + UserId);
            }
        }

        /// <summary>
        /// 是否在其它终端登录
        /// </summary>
        /// <param name="userid">用户编号</param>
        /// <param name="appTermId">当前终端号</param>
        /// <returns>在其它地方登录则返回AppTermId，否则为空</returns>
        public string IsLoginOther(int userid, string appTermId)
        {
            using (DBContext context = new DBContext())
            {
                object scalar = context.ExecScalar("select AppTermId from A0_Users where userid = " + userid + " and  AppTermId is not null and AppTermId <> '" + appTermId + "'");
                if (scalar == null || scalar == DBNull.Value) return null;
                else return scalar.ToString();
            }
        }

        /// <summary>
        /// 获取管理员角色
        /// </summary>
        /// <returns></returns>
        public Role GetAdministrator()
        {
            return Context.QuerySingle<Role>(new { Name = "administrators", IsSystem = 1 }, null, null, "没有配置administrators角色");
        }

        public virtual BaseUser GetUserByAccount(string username)
        {
            if (string.IsNullOrEmpty(username)) throw new ClientException("用户名不能为空!");
            QueryParam qp = new QueryParam() { entityType = Context.Membership.UserType };
            if (IsEmail(username))
            {
                qp.AddWhere("Email", username);
            }
            else if (IsMobile(username))
            {
                qp.AddWhere("Mobile", username);
            }
            else
            {
                qp.AddWhere("Account", username);
            }
            //qp.AddWhere("Status", "> -1");
            return Context.DoGetOne(qp, "账号不存在，请重新输入") as BaseUser;
        }


        /// <summary>
        ///AgencyCode  不为空为代理商   ""是不是代理商
        /// <param name="Password">可以是明文，也可以是完整md5大写</param>
        /// </summary>
        public virtual BaseUser CheckLogin(string username, string Password)
        {
            BaseUser u = GetUserByAccount(username);
            //if (u.Status < 0) throw new ClientException("您已被限制登录！");
            if (Password.Length == 32) Password = Password.Substring(5, 20);
            else Password = QQZiFramework.Utility.EncryptMD5_QQZI(Password);
            if (!u.Password.Equals(Password))
            {
                throw new PasswordErrorException(u.UserId);
            }
            else
            {
                if (u.Status< 0) throw new ClientException("账户已被冻结，无法登录。请联系客服。");
                return u;
            }
        }

        public static bool IsEmail(string email)
        {
            return System.Text.RegularExpressions.Regex.IsMatch(email, @"\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*");
        }

        public static bool IsMobile(string mobile)
        {
            return System.Text.RegularExpressions.Regex.IsMatch(mobile, @"^1[3456789]\d{9}$");
        }

        public void SaveUserRecord(int UserId, int Device, int ActionType, int isAdmin, string Terminal, string client, string ip, string CityId, string Location, string Coordinates = "")
        {
            LoginRecords lg = new LoginRecords();
            lg.UserId = UserId;
            lg.CreateTime = DateTime.Now;
            lg.Device = Device;
            lg.ActionType = ActionType;
            lg.isAdmin = isAdmin;
            lg.Terminal = Terminal;
            lg.Client = client;
            lg.CityId = CityId;
            lg.Coordinates = Coordinates;
            lg.Location = Location;
            lg.Ip = ip;
            Context.DoSave(lg);
        }
    }
}
